/*
    日志格式类：按照格式化字符串打印日志信息
*/
#ifndef __M_FORMATTER_H__
#define __M_FORMATTER_H__
#include <iostream>
#include <string>
#include <time.h>
#include <vector>
#include <assert.h>
#include <sstream>
#include "message.hpp"
#include "level.hpp"
namespace zxlog
{
    class FormaItem
    {
    public:
        using ptr = std::shared_ptr<FormaItem>;
        virtual ~FormaItem() {}
        virtual void format(std::ostream &os, const LogMsg &msg) {}
    };
    // 输出有效载荷
    class MsgFormaItem : public FormaItem
    {
    public:
        void format(std::ostream &os, const LogMsg &msg) override
        {
            os << msg._payload;
        }
    };
    // 输出日志等级
    class LevelFormaItem : public FormaItem
    {
    public:
        void format(std::ostream &os, const LogMsg &msg) override
        {
            os << LogLevel::toString(msg._level);
        }
    };
    // 输出日志器名称
    class NameFormaItem : public FormaItem
    {
    public:
        void format(std::ostream &os, const LogMsg &msg) override
        {
            os << msg._name;
        }
    };
    // 输出日志器ID
    class ThreadFormaItem : public FormaItem
    {
    public:
        void format(std::ostream &os, const LogMsg &msg) override
        {
            os << msg._pid;
        }
    };
    // 按照格式化输出时间
    class TimeFormaItem : public FormaItem
    {
    private:
        std::string _formatter;

    public:
        TimeFormaItem(const std::string &formatter = "%H:%M:%S") : _formatter(formatter) {}
        void format(std::ostream &os, const LogMsg &msg) override
        {
            time_t ctime = msg._ctime;
            struct tm l;
            localtime_r(&ctime, &l);
            char tmp[128];
            strftime(tmp, 127, _formatter.c_str(), &l);
            os << tmp;
        }
    };
    // 输出文件名
    class CFileFormaItem : public FormaItem
    {
    public:
        void format(std::ostream &os, const LogMsg &msg) override
        {
            os << msg._file;
        }
    };
    // 输出tab
    class TabFormaItem : public FormaItem
    {
    public:
        void format(std::ostream &os, const LogMsg &msg) override
        {
            os << "  ";
        }
    };
    // 打印行号
    class ClineFormaItem : public FormaItem
    {
    public:
        void format(std::ostream &os, const LogMsg &msg) override
        {
            os << msg._line;
        }
    };
    // 打印换行
    class NlineFormaItem : public FormaItem
    {
    public:
        void format(std::ostream &os, const LogMsg &msg) override
        {
            os << "\n";
        }
    };
    // 输出其他字符
    class OtherFormaItem : public FormaItem
    {
    private:
        std::string _str;

    public:
        OtherFormaItem(const std::string &str) : _str(str) {}
        void format(std::ostream &os, const LogMsg &msg) override
        {
            os << _str;
        }
    };
    class Formatter
    {
    public:
        /*
            %d 日期
            %T 缩进
            %t 线程id
            %p 日志级别
            %c 日志器名称
            %f 文件名
            %l 行号
            %m 日志消息
            %n 换行
        */
        // 时间{年-月-日 时:分:秒}缩进 线程ID 缩进 [日志级别] 缩进 [日志名称] 缩进 文件名:行号 缩进 消息换行
        using ptr = std::shared_ptr<Formatter>;
        // 默认格式化字符
        Formatter(const std::string &pattern = "[%d{%H:%M:%S}]%T%t%T[%p]%T[%c]%T%f:%l%T%m%n")
            : _pattern(pattern)
        {
            assert(ParserPattern());
        }
        // 将格式化好的字符串写入string中
        std::string format(const LogMsg &msg)
        {
            std::stringstream ss;
            for (auto &item : _items)
            {
                item->format(ss, msg);
            }
            return ss.str();
        }
        // 将格式化好的字符串写入iostream流中
        std::ostream &format(std::ostream &os, const LogMsg &msg)
        {
            for (auto &item : _items)
            {
                item->format(os, msg);
            }
            return os;
        }

    private:
        bool ParserPattern()
        {
            size_t pos = 0;
            std::string key;
            std::string val;
            while (pos < _pattern.size())
            {
                if (_pattern[pos] != '%')
                {
                    val.push_back(_pattern[pos++]);
                    continue;
                }
                if (pos + 1 < _pattern.size() && _pattern[pos + 1] == '%')
                {
                    val.push_back(_pattern[pos + 1]);
                    pos += 2;
                    continue;
                }
                if (val.empty() == false)
                {
                    _items.push_back(CreatItem(key, val));
                    val.clear();
                }
                // 走到这里pos位置上就是%
                pos += 1;
                // 走到这里pos位置上就是格式化字母,d/T...
                // 检查是否走到末尾
                if (pos >= _pattern.size() || !isalpha(_pattern[pos]))
                {
                    std::cerr << _pattern[pos - 1] << "位置附近格式错误" << std::endl;
                    return false;
                }
                else
                {
                    key.push_back(_pattern[pos]);
                }
                // 检查花括号{}
                if (pos + 1 < _pattern.size() && _pattern[pos + 1] == '{')
                {
                    pos += 2; // 该位置为{
                    while (pos < _pattern.size() && _pattern[pos] != '}')
                    {
                        val.push_back(_pattern[pos]);
                        pos++;
                    }
                    if (pos >= _pattern.size())
                    {
                        std::cerr << "{}匹配错误!" << std::endl;
                        return false;
                    }
                    // 走到这里,pos位置一定是}
                }
                _items.push_back(CreatItem(key, val));
                val.clear();
                key.clear();
                pos += 1;
            }
            return true;
        }
        FormaItem::ptr CreatItem(const std::string &key, const std::string &val)
        {
            if (key == "T")
                return std::make_shared<TabFormaItem>();
            if (key == "t")
                return std::make_shared<ThreadFormaItem>();
            if (key == "p")
                return std::make_shared<LevelFormaItem>();
            if (key == "c")
                return std::make_shared<NameFormaItem>();
            if (key == "f")
                return std::make_shared<CFileFormaItem>();
            if (key == "l")
                return std::make_shared<ClineFormaItem>();
            if (key == "m")
                return std::make_shared<MsgFormaItem>();
            if (key == "n")
                return std::make_shared<NlineFormaItem>();
            if (key == "d")
                return std::make_shared<TimeFormaItem>(val);
            return std::make_shared<OtherFormaItem>(val);
        }

    private:
        // 默认格式 "%d{%H:%M:%S}%T%t%T[%p]%T[%c]%T%f:%l%T%m%n"
        std::string _pattern; // 存放格式化字符串
        std::vector<FormaItem::ptr> _items;
    };
}
#endif